API Reference
Overview of the Rezolve Ai v1 API, authentication, scopes, jobs, and errors.
The v1 API covers the Contextual Enrichment Engine, product lookup, durable jobs, account usage, utilities, feeds, projects, partner tenants, ratings, and webhooks. Each endpoint has its own reference page in this section with parameters, schemas, request samples, and a live request panel. This page covers the parts that apply across all of them.
Base URL
https://ace.authoritas.com/api/v1
All paths below are relative to that base. For a machine readable description, GET /api/v1/openapi returns the full OpenAPI 3.0 spec.
Authentication
Every endpoint that requires auth accepts an API key in either header:
Authorization: Bearer <your-api-key>X-API-Key: <your-api-key>
No key is needed for GET /api/v1/health or GET /api/v1/openapi. Create and manage keys under Settings, Developer console, Keys. See API Keys for details.
A partner account can also name the tenant a call is for with an X-Tenant-Id header, on any endpoint that takes an API key. See the Partner API guide.
One endpoint is not authenticated with an API key at all: POST /feeds/{id}/events is signed with the feed's own ingest secret. See the Feeds API guide.
Scopes
Each endpoint below checks for one scope. admin satisfies every check, and a write scope also satisfies the matching read check.
| Scope | Endpoints that check it |
|---|---|
enrichment:read | GET /jobs, GET /jobs/{id}, GET /jobs/{id}/results, GET /usage, GET /enrichment/lookup, GET /enrichment/lookup/sources |
enrichment:write | POST /enrichment/rules, POST /enrichment/content, POST /enrichment/pipeline, POST /enrichment/lookup, POST /jobs/{id}/cancel |
utils:read | POST /utils/language, POST /utils/agentic-readiness, POST /utils/review-quality. These also accept enrichment:read or enrichment:write. |
feeds:read | GET /feeds, GET /feeds/{id}, GET /feeds/{id}/source, GET /feeds/{id}/delivery, GET /feeds/{id}/export, GET /feeds/{id}/enrichments |
feeds:write | POST /feeds, DELETE /feeds/{id}, PUT /feeds/{id}/source, POST /feeds/{id}/source, PUT /feeds/{id}/delivery |
webhooks:read | GET /webhooks, GET /webhooks/{id}, GET /webhooks/{id}/deliveries |
webhooks:write | POST /webhooks, PUT /webhooks/{id}, DELETE /webhooks/{id} |
ratings:read | GET /ratings/{productId} |
ratings:write | POST /ratings/ingest |
admin | Every v1 endpoint. Grants all other scopes. It is also the only scope that can create, rename, or delete a project: POST /projects, PUT /projects/{id}, DELETE /projects/{id}. On a partner account, an account-wide admin key is the one that manages tenants: every /tenants endpoint. |
GET /projects and GET /projects/{id} accept any valid key, because they are how a caller finds the project ids the other endpoints ask for. A key pinned to a project sees only that project, and cannot create another.
The feeds, projects, and webhooks endpoints also accept a signed-in session, which is how the dashboard calls them. A session is not checked for scopes.
New keys get enrichment:read, enrichment:write, and utils:read by default. A call without the scope it needs returns 403 FORBIDDEN.
Endpoints
Enrichment: Health check, Generate contextual rules, Generate rules-grounded content, Run the full enrichment pipeline, Look up products by identifier, Look up one product, free, List the lookup sources you can use. See the Contextual Enrichment Engine and the product lookup guide.
Jobs: List enrichment jobs, Get a job, Get paginated job results, Cancel a job.
Account: Usage snapshot.
Utilities: Detect feed language, Score agentic readiness, Score review quality.
Feeds: List feeds, Create a feed, Get a feed, Delete a feed, Read a feed's source settings, Set a feed's source URL and schedule, Refresh now, or rotate the ingest secret, Push changed products, Read a feed's delivery settings, Publish a feed to channel URLs, Download a channel feed, Read generated content per field. See the Feeds API guide.
Projects: List projects, Create a project, Get a project, Update a project, Delete a project.
Tenants (partner accounts): List tenants, Create a tenant, Get a tenant, Update a tenant, Delete a tenant, List a tenant's keys, Create a tenant key, Revoke a tenant key, Rotate a tenant key, Get a tenant's usage. See the Partner API guide.
Ratings: Send customer ratings and reviews, Get resolved ratings for a product.
Webhooks: List webhook subscriptions, Create a webhook subscription, Get a webhook subscription, Update a webhook subscription, Delete a webhook subscription, List webhook deliveries. See the webhooks guide.
Content types
Use these values in the contentTypes array for POST /enrichment/content and POST /enrichment/pipeline.
| Content type | API value |
|---|---|
| Product description | product-description |
| Meta tags and SEO | meta-tags |
| Enhanced JSON-LD schema | jsonld-schema |
| IRL scenario cards | irl-scenarios |
| Internal linking recommendations | internal-links |
| Product title | product-title |
| Highlights and bullet points | highlights |
| Product Q&A | product-qa |
| Product attributes | product-attributes |
| Image alt text | image-alt |
| Google Shopping feed fields | google-shopping |
| Agentic Commerce feed fields | agentic-commerce |
| Microsoft Shopping feed fields | microsoft-shopping |
| Shopify feed fields | shopify |
| WooCommerce feed fields | woocommerce |
A value that is not in this table is skipped rather than rejected, and is listed in skippedContentTypes (on a synchronous response, or on the job's result) so you can see it was not generated or charged. image-alt needs at least one product image with a public URL.
Leave contentTypes out of a pipeline request and it generates product-description, meta-tags, jsonld-schema, and irl-scenarios.
Synchronous and asynchronous requests
POST /enrichment/pipeline always runs as a durable job: it answers 202 with a job envelope.
POST /enrichment/rules and POST /enrichment/content decide from the size of the request:
rulesanswers inline for up to 5 products.contentanswers inline for up to 5 products and up to 10 units (products multiplied by content types).- A
storesource always becomes a job.
Anything larger returns 202 with a job envelope. Send "mode": "async" to force a job, or "mode": "sync" to require an inline result. An inline content response is 200, or 207 when some units failed.
POST /enrichment/lookup works the same way. It answers inline for up to 5 products, or 3 when a page is read or the web is searched for each one, and returns a job beyond that.
Poll a job with GET /jobs/{id}, or subscribe to webhooks and skip polling. A job's status is one of pending, running, completed, partial, failed, or cancelled.
Idempotency
Send an Idempotency-Key header (up to 255 characters) on a request that creates a job to make a retry safe. A repeat with the same key returns the original job instead of starting a second one, including while that job is still running: a retry is not refused as a second run. The header has no effect on a request that is answered inline.
Responses
Success responses use { "data": ... }. List endpoints that page by number add meta.pagination with page, pageSize, total, and totalPages. GET /feeds/{id}/enrichments pages by cursor instead and adds meta.cursor with limit, hasMore, and nextCursor. GET /feeds/{id}/export returns the feed file itself, not a JSON envelope.
Responses from the endpoints that check a scope carry an X-Request-Id header. Quote it when you report a problem.
Key management
These endpoints manage API keys for the currently signed-in user. They use session (cookie) auth, not an API key, so call them from a page or script that shares the browser session.
| Method | Path | Purpose |
|---|---|---|
| GET | /api/keys | List keys for the project you are working in, plus account-wide keys (metadata only). |
| POST | /api/keys | Create a key. Body: name (required), optional env, scopes, rate_limit_per_minute, expires_at, project_id. The plain key is returned only on create. |
| GET | /api/keys/[id] | Get one key by ID (metadata only). |
| PATCH | /api/keys/[id] | Update a key's name, scopes, rate_limit_per_minute, or expires_at. |
| DELETE | /api/keys/[id] | Revoke the key. |
| POST | /api/keys/[id]/rotate | Issue a successor key. Body: optional graceHours (default 24). The old key works until the grace period ends. |
See API Keys for the fields.
Rate limits
Each key has a requests per minute limit: 120 by default for a live key, and at most 20 for a test key. Responses carry X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset. When the limit is exceeded, the API returns 429 with a Retry-After header. See API Keys for how to set a different limit.
Errors
Errors use the shape { "error": { "code": "...", "message": "...", "details": ... } } with these HTTP statuses:
| Status | Meaning |
|---|---|
| 400 | Invalid request or validation error |
| 401 | Missing, invalid, or expired API key |
| 402 | Insufficient credits, test quota exhausted, or subscription required |
| 403 | Forbidden: a missing scope, or a pinned key naming another project |
| 404 | No such resource, or it belongs to another account |
| 409 | An enrichment run is already active for the project |
| 413 | Request body too large |
| 429 | Rate limit exceeded |
| 500 | Server error |
Error codes
| Code | Status | When |
|---|---|---|
VALIDATION_ERROR | 400 | The body or query failed validation. details lists the problems. |
BAD_REQUEST | 400 | The request is well formed but cannot be acted on, for example an unknown export channel. |
PROJECT_ID_REQUIRED | 400 | The endpoint returns project-scoped rows and the request named no project. Applies to an account-wide key that omitted projectId. |
UNAUTHORIZED | 401 | No key, an invalid or revoked key, or an expired one. On POST /feeds/{id}/events, the signature did not verify. |
INSUFFICIENT_CREDITS | 402 | A live key's credit balance is empty. |
TEST_QUOTA_EXCEEDED | 402 | A test key has used its monthly requests or units. |
SUBSCRIPTION_REQUIRED | 402 | The project bills through Shopify and cannot run AI work yet. The message says why. |
FORBIDDEN | 403 | The key lacks the scope the endpoint checks. |
PROJECT_SCOPE_MISMATCH | 403 | The key is pinned to one project and the request named a different one. |
PARTNER_REQUIRED | 403 | A /tenants endpoint or the X-Tenant-Id header was used by an account that is not a partner, or a tenant endpoint was called with a key other than the partner's account-wide admin key. |
TENANT_SUSPENDED | 403 | The tenant the call is for is suspended. |
TENANT_NOT_FOUND | 404 | X-Tenant-Id or the path names no tenant on this account. |
TENANT_LIMIT_REACHED | 409 | The partner account holds as many tenants as it is allowed. |
NOT_FOUND | 404 | No such resource for this account. |
RUN_ALREADY_ACTIVE | 409 | POST /enrichment/pipeline, or a POST /enrichment/content request that would become a job, was refused because another enrichment run is in progress for the project. Nothing is charged. |
PAYLOAD_TOO_LARGE | 413 | A POST /ratings/ingest body over 3MB. |
RATE_LIMIT_EXCEEDED | 429 | The key's requests per minute limit was reached. |
NO_IDENTIFIER | 400 | A lookup request carried nothing that can be looked up. |
INVALID_IDENTIFIER | 400 | Every identifier in a lookup request failed validation, for example a barcode with a wrong check digit. details gives the reason for each. |
SOURCE_UNAVAILABLE | 400 | None of the lookup sources the request named is available to the key. details gives the reason for each. |
LOOKUP_CONCURRENCY_LIMIT | 429 | Three lookup jobs are already queued or running for the account. |
SERVER_ERROR | 500 | Something failed on our side. Retry, and quote the X-Request-Id header if it persists. |
PROJECT_ID_REQUIRED
{
"error": {
"code": "PROJECT_ID_REQUIRED",
"message": "This endpoint returns project-scoped data. Pass ?projectId=<id>, or use a key pinned to a project."
}
}Why you may be seeing this now. GET /feeds and GET /feeds/{id} used to
answer an account-wide key with no projectId by merging rows from every
project on the account. Nothing in the response said which project each row came
from, so there was no safe way to read it. They now ask you to name one. POST /feeds asks the same of an account-wide key, with projectId in the body.
Two ways to fix it, both one-time:
- add
?projectId=<id>to the request. Ids come fromGET /projects. - or create a key pinned to a project in Settings, Developer console, Keys, and leave the parameter off.
PROJECT_SCOPE_MISMATCH
{
"error": {
"code": "PROJECT_SCOPE_MISMATCH",
"message": "This API key is scoped to a different project."
}
}A pinned key may only act on its own project. Use an account-wide key, or a key pinned to the project you are addressing.