We build custom applications 5x faster and cheaper 🚀
Book a Free Consultation
Stuck on an error? Book a 30-minute call with an engineer and get a direct fix + next steps. No pressure, no commitment.
To integrate Ai Ppt Generator with OpenClaw, build a small external service that handles OAuth/API-key authentication, calls the Ai Ppt Generator REST API to create PPT files, stores or streams generated files (S3 or similar), and exposes secure webhook/callback and REST endpoints that your OpenClaw skill (registered in ClawHub) will invoke. Keep all long-running work and stateful storage outside the agent runtime, implement proper token handling and webhook validation, and configure the skill in ClawHub with the correct redirect URIs, scopes, and API credentials so OpenClaw can invoke your skill actions reliably.
Notes: Replace <AI_PPT_API\_BASE>, client IDs, secrets, and storage endpoints with vendor-provided values. These examples use generic OAuth token exchange, job creation, and webhook verification patterns—adapt to the actual Ai Ppt Generator API spec.
const express = require('express');
const fetch = require('node-fetch');
const crypto = require('crypto');
// load secrets from environment
const {
AI_PPT_CLIENT\_ID,
AI_PPT_CLIENT\_SECRET,
AI_PPT_API\_BASE, // e.g. https://api.vendor.example
WEBHOOK\_SECRET,
S3_PRESIGN_ENDPOINT
} = process.env;
const app = express();
app.use(express.json());
// OAuth token exchange endpoint (called by your browser redirect after user authorizes)
app.post('/oauth/callback', async (req, res) => {
const { code, redirect\_uri } = req.body;
// Exchange code for tokens
const tokenResp = await fetch(`${AI_PPT_API_BASE}/oauth/token`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
grant_type: 'authorization_code',
code,
client_id: AI_PPT_CLIENT_ID,
client_secret: AI_PPT_CLIENT_SECRET,
redirect\_uri
})
});
const tokenJson = await tokenResp.json();
// Persist tokenJson (access_token, refresh_token, expires\_in) associated with user
// saveTokensForUser(userId, tokenJson);
res.json({ ok: true });
});
// Start PPT generation (called by OpenClaw skill endpoint)
app.post('/generate', async (req, res) => {
const { userId, title, prompts } = req.body;
// Retrieve stored access token for user
// const { access\_token } = await getTokensForUser(userId);
const access_token = 'REPLACE_WITH_REAL_TOKEN';
// Request generation from Ai Ppt Generator
const createResp = await fetch(`${AI_PPT_API_BASE}/v1/generate`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${access_token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ title, prompts, output\_format: 'pptx' })
});
const job = await createResp.json();
// Persist job.id and return job handle to agent
res.json({ jobId: job.id });
});
// Webhook: Ai Ppt Generator notifies when file is ready
app.post('/webhook/ai-ppt', async (req, res) => {
const signature = req.header('X-Signature') || '';
const payload = JSON.stringify(req.body);
// Verify HMAC signature (vendor should supply signing secret or public key)
const expected = crypto.createHmac('sha256', WEBHOOK\_SECRET).update(payload).digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature))) {
return res.status(401).send('invalid signature');
}
const { jobId, fileUrl } = req.body;
// Save fileUrl for job, optionally move file into controlled storage
// saveJobResult(jobId, fileUrl);
// Optionally issue a presigned S3 URL or transfer to your storage and notify OpenClaw runtime/user
res.status(200).send('ok');
});
app.listen(3000);
const AWS = require('aws-sdk');
const s3 = new AWS.S3();
async function fetchAndStoreToS3(sourceUrl, bucket, key) {
// Fetch the generated file from vendor URL
const r = await fetch(sourceUrl);
if (!r.ok) throw new Error('failed to fetch generated file');
const buffer = await r.buffer();
// Upload to S3 (private)
await s3.putObject({
Bucket: bucket,
Key: key,
Body: buffer,
ContentType: 'application/vnd.openxmlformats-officedocument.presentationml.presentation'
}).promise();
// Generate presigned GET URL (valid for limited time)
const url = s3.getSignedUrl('getObject', { Bucket: bucket, Key: key, Expires: 60 \* 60 });
return url;
}
Speak one‑on‑one with a senior engineer about your no‑code app, migration goals, and budget. In just half an hour you’ll leave with clear, actionable next steps—no strings attached.
1
Â
Return 401 Unauthorized for Ai Ppt Generator requests that present an OpenClaw CLI token because CLI tokens commonly lack the runtime API scopes or are invalid for service-to-service calls; reject them at the API boundary and log the mismatch.
Â
// Minimal Express middleware to reject CLI tokens
const expectedType = process.env.EXPECTED_TOKEN_TYPE || 'service';
// <b>//</b> assume token format: type:value (example policy)
function rejectCliToken(req,res,next){
 const auth = req.get('Authorization') || '';
 if(!auth.startsWith('Bearer ')) return res.status(401).send('Unauthorized');
 const token = auth.slice(7);
 // <b>//</b> simple heuristic: CLI tokens start with "cli_"
 if(token.startsWith('cli_')) return res.status(401).send('Unauthorized: CLI token not allowed');
 next();
}
2
 Expose your Ai Ppt Generator callback by creating a stable public URL (reverse proxy, dynamic DNS + port-forward, or tunnel), terminate TLS there, forward to the OpenClaw agent runtime preserving headers (X-Forwarded-For/Proto), register that URL in ClawHub/skill config, and protect callbacks with a secret token or signature verified by the skill. Log and validate payloads, and use healthchecks/retries.
Â
3
Most likely the PPTX is corrupted because binary data is being transformed or truncated between the Ai Ppt Generator and the OpenClaw task runtime (wrong encoding, missing Content-Length, text-mode transport, closed stream too early, or runtime size limits). Return the file as base64, set proper headers, or store the file externally and return a URL.
Check:
4
Â
Handle 429s by honoring Retry-After, using exponential backoff with jitter, queueing requests (so workers rate-limit), using idempotency keys for safe retries, and recording metrics + circuit-breaker to prevent overload. Implement retries in your job-submitter (or workflow worker) and move heavy retry/state to external queue or service outside the agent runtime.
Â
async function submitJob(payload){
 const max=6;
 for(let i=1;i<=max;i++){
  const res=await fetch(URL, {method:'POST', headers:{'Authorization':`Bearer ${process.env.AI_KEY}`,'Content-Type':'application/json'}, body:JSON.stringify(payload)});
  if(res.status===202) return await res.json();
  if(res.status!==429) throw new Error('submit failed '+res.status);
  const ra=res.headers.get('Retry-After');
  const delay=ra?parseFloat(ra)*1000:Math.min(1000*Math.pow(2,i),30000);
  const jitter=Math.random()*500;
  await new Promise(r=>setTimeout(r, delay + jitter));  <b>//</b> retry after delay
 }
 throw new Error('max retries reached');
}
This prompt helps an AI assistant understand your setup and guide you through the fix step by step, without assuming technical knowledge.
From startups to enterprises and everything in between, see for yourself our incredible impact.
Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We’ll discuss your project and provide a custom quote at no cost.Â