Skip to content
The Public API is available on request. Email support@grona.ai to get access.

Create an editor link

POST
/v1/variations/edit-link
curl --request POST \
--url https://api.grona.ai/v1/variations/edit-link \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "variationId": "671a3c90e4b0a1f2c3d40012" }'

Returns a new editor link for a variation. The token in the link expires 15 minutes after generatedAt. generatedAt and expiresAt describe editUrl only and are read from the token itself, so they always agree with the link.

The token travels in the query string. Open the link right away and do not store, log or forward it.

Media typeapplication/json
object
variationId
required

A variation id from variations[].id on create, list or get.

string

Example

{
"variationId": "671a3c90e4b0a1f2c3d40012"
}

OK.

Media typeapplication/json
object
data
required
object
editUrl
required

Editor link. Its token expires 15 minutes after generatedAt.

string format: uri
variationId
required
string
previewUrl
required

The page with the variation’s saved changes applied. It does not expire.

string format: uri
generatedAt
required

ISO 8601 in UTC, with millisecond precision.

string format: date-time
expiresAt
required

ISO 8601 in UTC, with millisecond precision.

string format: date-time
meta
required
object
workspaceId
required

The workspace resolved from the secret key.

string

Example

{
"data": {
"editUrl": "https://api.grona.ai/v1/editor/launch?token=eyJhbGciOi...",
"variationId": "671a3c90e4b0a1f2c3d40012",
"previewUrl": "https://shop.example.com/?gronaPreview=671a3c90e4b0a1f2c3d40012",
"generatedAt": "2026-10-20T11:12:05.614Z",
"expiresAt": "2026-10-20T11:27:05.614Z"
},
"meta": {
"workspaceId": "65e8a1c47d2f9b03e6a15c42"
}
}

variationId is missing or is not a valid id. error.code is invalid_request.

Media typeapplication/json
object
error
required
object
code
required

Stable and machine-readable. Branch on this, and on the HTTP status for codes you do not know.

string
Allowed values: invalid_request unauthorized not_found conflict internal_error
message
required

Human-readable. The wording can change, so do not parse it.

string

Example

{
"error": {
"code": "invalid_request",
"message": "`variationId` is not a valid id."
}
}

The secret key is missing, malformed, unknown or revoked. error.code is unauthorized.

Media typeapplication/json
object
error
required
object
code
required

Stable and machine-readable. Branch on this, and on the HTTP status for codes you do not know.

string
Allowed values: invalid_request unauthorized not_found conflict internal_error
message
required

Human-readable. The wording can change, so do not parse it.

string

Example

{
"error": {
"code": "unauthorized",
"message": "Missing or invalid API key."
}
}

No variation with this id exists in the key’s workspace, for example because its campaign was deleted. error.code is not_found.

Media typeapplication/json
object
error
required
object
code
required

Stable and machine-readable. Branch on this, and on the HTTP status for codes you do not know.

string
Allowed values: invalid_request unauthorized not_found conflict internal_error
message
required

Human-readable. The wording can change, so do not parse it.

string

Example

{
"error": {
"code": "not_found",
"message": "Variation not found."
}
}

Too many requests. Retry with exponential backoff and jitter, and wait at least as long as Retry-After when it is present. Branch on the status code; the body is not guaranteed to use the error envelope.

Retry-After
string

How long to wait before retrying, in seconds or as an HTTP date.

Unexpected server error. error.code is internal_error. Retry with backoff; if it persists, contact support@grona.ai with the time of the request and the endpoint.

Media typeapplication/json
object
error
required
object
code
required

Stable and machine-readable. Branch on this, and on the HTTP status for codes you do not know.

string
Allowed values: invalid_request unauthorized not_found conflict internal_error
message
required

Human-readable. The wording can change, so do not parse it.

string

Example

{
"error": {
"code": "internal_error",
"message": "Something went wrong on our side."
}
}

Temporarily unavailable. Retry with exponential backoff and jitter, and wait at least as long as Retry-After when it is present. Branch on the status code; the body is not guaranteed to use the error envelope.

Retry-After
string

How long to wait before retrying, in seconds or as an HTTP date.