Integráció indítása
- Kérje meg egy rendszergazdát, hogy hozza létre az alkalmazását az Admin → API és integrációk menüpontban. Minden alkalmazáshoz külön környezet, tartalmi hatókörök, csatornák, nyelvek, szerzők, lejárat és kérési kvóta tartozik.
- A hitelesítő adatot a szerverén tárolja. Éles környezetben ft_live_ hitelesítő adatok, tesztkörnyezetben pedig ft_test_ használatosak. Minden kéréshez küldje el az Authorization: Bearer <credential> fejlécet.
- Olvassa be a /capabilities és /content/taxonomies végpontokat az engedélyezett szerző- és témaazonosítók lekéréséhez. A dokumentum előkészítéséhez használja az OpenAPI-sémát.
- Hozzon létre egy piszkozatot, küldje be ellenőrzésre, és figyelje a közzétételi eseményeket. Az automatizálás előkészítheti a hasznos tartalmat, de a közzétételért továbbra is egy szerkesztő felel.
Alap URL: https://www.formtruth.com/integrations/v1
Tartalom és közzététel
Minden külső piszkozat megköveteli a jelenlegi tartalmának munkatársi jóváhagyását a közzététel előtt. A megjelölt emberi szerzői mód vagy az automatikus közzétételi beállítás nem biztosít szerkesztői jóváhagyást.
A bejegyzések, vásárlói útmutatók és GYIK-ek egyetlen dokumentumformátumot és verzióelőzményt használnak. Használja a /content/posts, /content/guides vagy /content/faqs végpontot a megfelelő jogosultsággal. Az alkalmazások csak az általuk birtokolt tartalomhoz férhetnek hozzá; egy privát piszkozat olvasása nem azonos a közzétett webhely olvasásával.
A dokumentumok forrásnyelvet, valódi szerzőt, témákat, forrásokat, valamint lokalizált címeket, slugokat, összefoglalókat és strukturált szövegtörzsblokkokat tartalmaznak. A mesterséges intelligenciával támogatott vagy automatizált cikkeknek meg kell határozniuk az olvasó célját és az eredeti hozzájárulást. A fordítási módosítások nem változtathatják meg a termék tényeit, a számokat, a képazonosítókat, a hivatkozásokat vagy a szerkezeti méreteket.
Minden íráshoz szükség van Idempotency-Key kulcsra. A frissítés, ellenőrzés, közzététel és visszavonás esetén szükség van If-Match fejlécre is az idézett ETag értékkel. Az ellenőrzött tartalom szerkesztése érvényteleníti az érintett jóváhagyást. A forrás módosítása elavulttá teszi az érintett fordításokat, amíg azokat össze nem hangolják és újra el nem bírálják.
A feltöltött képek jóváhagyatlanok maradnak, amíg egy szerkesztő nem ellenőrzi a jogokat és a minőséget. A közzétett kiadások módosíthatatlan pillanatképek. A visszavonás eltávolítja a kiadást a nyilvános tartalomból, a hírcsatornákból és a keresési találatokból.
API-referencia
Az alábbi útvonalak az alap URL-hez képest értendők. Ugyanezek az útvonalak vonatkoznak az útmutatókra és a GYIK-ekre is, ha módosítja a tartalomcsaládot. Töltse le az OpenAPI-leírást a teljes kérési sémákhoz, a szükséges hatókörökhöz és a válaszokhoz.
| Módszer | Útvonal | Cél |
|---|
GET | /capabilities | Hatályos jogosultságai és korlátai |
GET / POST | /content/posts | Cikkei listázása / piszkozat létrehozása |
GET / PATCH | /content/posts/{id} | A piszkozat és az ETag megtekintése / egy változat mentése |
PUT | /content/posts/by-external-id/{externalId} | Piszkozat létrehozása vagy frissítése az Ön stabil külső azonosítójával |
POST | /content/posts/{id}/submit-review | Beküldés szerkesztői ellenőrzésre |
POST | /content/posts/{id}/publications | Jóváhagyott nyelvek közzététele vagy közzététel ütemezése |
DELETE | /content/posts/{id}/publications/{releaseId} | Közzététel visszavonása indoklással |
GET | /content/taxonomies | Aktív témák és engedélyezett szerzők |
POST | /content/imports | Legfeljebb 50 piszkozat sorba állítása és az egyes elemek eredményének megtekintése |
POST | /assets/uploads | Kép feltöltése jogi és minőségi ellenőrzésre |
POST | /assets/{id}/complete | A mentett feltöltési állapot megtekintése |
GET | /jobs/{id} | Importálási eredmények megtekintése |
GET / POST | /webhooks/subscriptions | HTTPS eseménykezelők listázása vagy regisztrálása |
POST | /webhooks/subscriptions/{id} | Kulcs frissítése, cseréje vagy kézbesítés letiltása |
A katalógus, a rendelések és a készlet későbbi API-modulok számára vannak fenntartva. Ezek a v1 átjárón keresztül még nem érhetők el.
Hibák és újrapróbálkozások
Küldjön tömörítetlen UTF-8 JSON-t. A kérés törzs korlátjai 2 MiB a szokásos írásokhoz, 8 MiB az importálásokhoz és 18 MiB a kódolt képfeltöltésekhez; a törzsnek tíz másodpercen belül meg kell érkeznie. A 413 azt jelenti, hogy a törzs túl nagy, a 415 nem támogatott formátumot jelent, a 408 pedig azt jelenti, hogy a feltöltés túllépte az időkorlátot.
A hibák az error.code, az error.message, az adott esetben megjelenő mezőrészletek, a retryable és a request_id értéket adják vissza. Támogatási ügyintézéshez őrizze meg az X-Request-Id értéket. A 401 hitelesítőadat-problémát jelent; a 403 jogosultságot; a 412 megváltozott verziót; a 422 érvénytelen vagy nem kész tartalmat; a 428 pedig hiányzó előfeltételt jelent.
A 429 esetén tartsa be a Retry-After értékét. Átmeneti 503 vagy hálózati megszakadás esetén korlátozott visszalépéses késleltetéssel, ugyanazzal a kulccsal és bemenettel próbálkozzon újra. Más törzstartalomhoz új kulcs szükséges. 409 esetén egyeztesse az előző művelet állapotát ahelyett, hogy vaktában megismételné. Az importálás elemről elemre visszaadja az eredményeket a /jobs/{id} végponton.
Aláírt webhookok
Használjon nyilvános HTTPS-fogadót a 443 porton. Az események közé tartozik a content.review_required, a content.published, a content.withdrawn, a content.publication_failed és az import.completed. A nyers kérés törzsét az elemzése előtt ellenőrizze.
HMAC-SHA256(secret, timestamp + "." + event_id + "." + raw_body)
Olvassa be az X-Formtruth-Timestamp, az X-Formtruth-Event-Id és az X-Formtruth-Signature értékét. Utasítsa el az öt percnél régebbi vagy jövőbeli időbélyegeket. Az aláírás fejlécében a 24 órás kulcscsere-időszak alatt több, vesszővel elválasztott v1= érték is szerepelhet; fogadjon el minden érvényes aláírást a megőrzött kulcsokhoz.
Az eseményazonosítót az ismétlődések kiszűréséhez atomikusan mentse, helyezze sorba a feladatot, majd haladéktalanul adjon vissza 2xx értéket. A kézbesítés újrapróbálható, ezért egy ismétlődő esemény nem teheti lehetővé a közzétételt vagy a kétszeri terhelést. Az aláírási titkot az API-hitelesítő adattól elkülönítve tárolja.
Kódpéldák
Készítse elő a document.json fájlt a KnowledgeDocument-séma és a ténylegesen engedélyezett taxonómiaazonosítók használatával. Biztonságosan állítsa be a FORMTRUTH_API_TOKEN értéket a szerverén. Ezek a példák piszkozatot hoznak létre; a közzétételhez továbbra is szükség van az ellenőrzési folyamatra.
import { readFile } from "node:fs/promises"
import { randomUUID } from "node:crypto"
const base = process.env.FORMTRUTH_URL || "https://www.formtruth.com"
const token = process.env.FORMTRUTH_API_TOKEN
if (!token) throw new Error("Set FORMTRUTH_API_TOKEN in a secure environment")
const document = JSON.parse(await readFile("document.json", "utf8"))
// Persist the key before calling. Reuse it only for an identical retry.
const key = process.env.FORMTRUTH_REQUEST_KEY || randomUUID()
console.log("Request key:", key)
const response = await fetch(base + "/integrations/v1/content/posts", {
method: "POST",
headers: { Authorization: "Bearer " + token, "Content-Type": "application/json", "Idempotency-Key": key },
body: JSON.stringify({ channel: "b2b", external_id: document.locales[document.source_locale].slug, document }),
})
const result = await response.json()
if (!response.ok) throw new Error(JSON.stringify(result.error))
console.log("Draft:", result.entry.id, "ETag:", response.headers.get("etag"))
// Creating a draft does not publish it. Submit for editorial review separately.
import json, os, uuid, urllib.request, urllib.error
base = os.environ.get("FORMTRUTH_URL", "https://www.formtruth.com")
token = os.environ["FORMTRUTH_API_TOKEN"]
with open("document.json", encoding="utf-8") as source:
document = json.load(source)
# Persist this key before sending; reuse for an identical retry.
key = os.environ.get("FORMTRUTH_REQUEST_KEY", str(uuid.uuid4()))
print("Request key:", key)
payload = {"channel": "b2b", "external_id": document["locales"][document["source_locale"]]["slug"], "document": document}
request = urllib.request.Request(base + "/integrations/v1/content/posts",
data=json.dumps(payload, ensure_ascii=False).encode("utf-8"), method="POST",
headers={"Authorization": "Bearer " + token, "Content-Type": "application/json", "Idempotency-Key": key})
try:
with urllib.request.urlopen(request, timeout=45) as response:
result = json.load(response)
print("Draft:", result["entry"]["id"], "ETag:", response.headers.get("ETag"))
except urllib.error.HTTPError as error:
raise RuntimeError(error.read().decode("utf-8")) from error
# Creating a draft does not publish it. Submit for editorial review separately.
import { createHmac, timingSafeEqual } from "node:crypto"
export function verifyWebhook(rawBody, headers, secret, now = Date.now()) {
const timestamp = headers.get("x-formtruth-timestamp") || ""
const eventId = headers.get("x-formtruth-event-id") || ""
const signatures = (headers.get("x-formtruth-signature") || "").split(",")
if (!/^[0-9]{10}$/.test(timestamp) || !eventId || Math.abs(now - Number(timestamp) * 1000) > 300000) return false
const expected = createHmac("sha256", secret).update(timestamp + "." + eventId + ".").update(rawBody).digest()
return signatures.some(value => {
const part = value.trim()
if (!/^v1=[a-f0-9]{64}$/.test(part)) return false
const actual = Buffer.from(part.slice(3), "hex")
return actual.length === expected.length && timingSafeEqual(actual, expected)
})
}
// Verify the raw body BEFORE JSON parsing. Atomically record eventId in durable
// storage to deduplicate retries; enqueue accepted work, then return HTTP 2xx.
// During rotation both v1 signatures are sent for 24 hours.
import hashlib, hmac, re, time
def verify_webhook(raw_body, headers, secret, now=None):
timestamp = headers.get("x-formtruth-timestamp", "")
event_id = headers.get("x-formtruth-event-id", "")
signatures = headers.get("x-formtruth-signature", "").split(",")
current = time.time() if now is None else now
if not re.fullmatch(r"[0-9]{10}", timestamp) or not event_id or abs(current - int(timestamp)) > 300:
return False
signed = (timestamp + "." + event_id + ".").encode("utf-8") + raw_body
expected = hmac.new(secret.encode("utf-8"), signed, hashlib.sha256).hexdigest()
return any(re.fullmatch(r"v1=[a-f0-9]{64}", part.strip()) and hmac.compare_digest(part.strip()[3:], expected) for part in signatures)
# Normalize header names to lowercase. Verify raw bytes before parsing JSON.
# Atomically persist event_id for deduplication, enqueue work, then return 2xx.