AI 资讯
Track Email Opens From Your Agent's Outreach
You built an outreach agent, it sent 80 follow-ups this week, and you have no idea what happened to any of them. Did the prospect open the message? Click the demo link? Is the silence a "no" or a spam-folder problem? Without engagement signals, your agent is firing into the void and your follow-up logic is guesswork. The fix has two parts: turn tracking on when you send, and subscribe to the webhooks that report what recipients do. Tracking starts at send time, not after Opens, clicks, and replies are only reported for messages sent with tracking enabled — you can't retroactively track a message that's already out. On the Send Message request, pass a tracking_options object with three booleans plus an optional label that gets echoed back in every notification: curl --request POST \ --url 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/messages/send' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer <NYLAS_API_KEY>' \ --data-raw '{ "subject": "Quick follow-up on your trial", "body": "Thanks for trying us out. Reply or <a href=\"https://example.com/demo\">book a demo</a> when ready.", "to": [{ "name": "Kim Townsend", "email": "kim@example.com" }], "tracking_options": { "opens": true, "links": true, "thread_replies": true, "label": "trial-followup-q2" } }' The label is the piece agents should lean on: stamp it with your campaign ID or contact ID and every later notification carries it, so your handler matches events back to outreach state without storing a message-ID mapping. One caveat before you test: message tracking needs a production application — trial accounts get "Tracking options are not allowed for trial accounts" back. Three triggers, one endpoint Engagement events arrive over webhooks. Subscribe one HTTPS endpoint to all three triggers — message.opened , message.link_clicked , and thread.replied : curl --request POST \ --url 'https://api.us.nylas.com/v3/webhooks/' \ --header 'Content-Type: application/json' \ --header 'Autho
AI 资讯
Async APIs: The 202 Accepted + Polling Pattern for Long-Running Operations
Some API requests can't finish in time for a single HTTP response. Generating a report, transcoding a video, running a batch import — these take seconds or minutes, far longer than any client should hold a connection open for. If you try to do this work inside a normal request, you'll hit gateway timeouts, frustrated clients retrying half-finished jobs, and load balancers killing connections at 30 or 60 seconds. The fix is a well-established HTTP pattern: accept the work, hand back a receipt, and let the client poll for the result. Here's how to build it properly. The shape of the pattern The client POST s the job. The server validates it, enqueues it, and immediately returns 202 Accepted with a URL where the status lives. The client polls that status URL until the job is done (or failed ). When complete, the status response points to the finished resource. The key detail most implementations get wrong: 202 does not mean "success." It means "I accepted this and will work on it." The actual outcome arrives later. Step 1: Accept the job import express from " express " ; import { randomUUID } from " crypto " ; const app = express (); app . use ( express . json ()); const jobs = new Map (); // use Redis or a DB in production app . post ( " /v1/reports " , ( req , res ) => { const id = randomUUID (); jobs . set ( id , { status : " pending " , createdAt : Date . now (), result : null }); // Kick off work without blocking the response processReport ( id , req . body ). catch (( err ) => { jobs . set ( id , { status : " failed " , error : err . message }); }); res . status ( 202 ) . location ( `/v1/reports/ ${ id } ` ) . json ({ id , status : " pending " }); }); Notice the Location header. It tells the client exactly where to look — no need to construct the URL itself. Step 2: Expose a status endpoint app . get ( " /v1/reports/:id " , ( req , res ) => { const job = jobs . get ( req . params . id ); if ( ! job ) return res . status ( 404 ). json ({ error : " unknown job " })
AI 资讯
How API Testing Levelled Up My QA Career (And Why Most Engineers Skip It)
The Moment I Realised UI Testing Wasn't Enough Three years into my QA career, I thought I was doing well. I had a solid Selenium suite running. Regression coverage was green. Stakeholders were happy. Then a production incident happened. A payment API was returning incorrect amounts under a specific condition. The UI looked perfect — amounts displayed correctly after rounding. But the raw API response? Off by a significant margin. My entire test suite missed it. Every single test. Because I was only testing what users saw . Not what the system was actually doing . That incident changed how I approached QA forever. 👇 Why API Testing Is the Most Underrated Skill in QA Let me be direct about something. Most QA engineers treat API testing as a secondary skill. Something you do with Postman when a developer asks you to verify an endpoint. A quick sanity check before moving on. That's the wrong mental model entirely. Here's the truth after 7.5 years: The API layer is where your product actually lives. The UI is a presentation layer. It shows users a version of the truth. But the API? That's the truth itself. Data contracts, business logic, validation rules, error handling — all of it lives at the API layer. If you're only testing the UI, you're testing the packaging. Not the product. My API Testing Journey — Tool by Tool Let me walk you through exactly how my API testing practice evolved, and what each tool actually taught me. Stage 1 — Postman: Learning to Think in Requests Postman was my entry point. And it's still the tool I reach for first when exploring a new API. But most people use Postman wrong. They treat it like a manual testing tool — fire a request, check the response, move on. That's wasting 80% of what Postman can do. Here's how I actually use it: Collections + Environments = your real power combo // Environment variables — not hardcoded values {{ base_url }} /api/ v1 / users / {{ user_id }} // Switch between dev/staging/prod by changing one environment // No
AI 资讯
How a PHP SDK Can Save You Hundreds of Lines of API Integration Code
How a PHP SDK Can Save You Hundreds of Lines of API Integration Code Most APIs provide documentation, examples, and maybe even a Postman collection. That's usually enough to get started. But once your application grows, you'll quickly discover that working directly with HTTP requests introduces a surprising amount of repetitive code. You end up writing the same things over and over: Authentication headers Request serialization Response parsing Error handling Pagination logic DTO mapping This is exactly why SDKs exist. In this article, we'll look at how a PHP SDK can simplify API integrations and reduce maintenance costs over time. The Hidden Cost of Direct API Calls Let's imagine you're integrating a URL shortening API. A typical implementation might look like this: $client = new GuzzleHttp\Client (); $response = $client -> post ( 'https://example.com/api/links' , [ 'headers' => [ 'X-Api-Key' => $apiKey , 'Content-Type' => 'application/json' , ], 'json' => [ 'url' => 'https://example.com' ] ] ); $data = json_decode ( $response -> getBody () -> getContents (), true ); This doesn't seem bad. Now repeat it for: Create link Update link Delete link Get link List links Create group Update group Get profile Eventually your codebase becomes filled with API boilerplate. The business logic becomes harder to see because it's buried under HTTP implementation details. What a Good SDK Does A well-designed SDK abstracts repetitive tasks and exposes a clean programming interface. Instead of dealing with HTTP requests directly, developers work with resources and objects. For example: $link = $client -> links () -> create ([ 'url' => 'https://example.com' ]); This is easier to read and easier to maintain. The SDK becomes responsible for: Authentication Request building Validation Serialization Response mapping Exception handling Consistent Error Handling One common problem with raw API integrations is inconsistent error handling. Without an SDK, every request may need its own validat
AI 资讯
Why Most Sports Betting Projects Fail Before Launch (And It's Not the Algorithm)
If you've ever tried building a sports betting application, odds tracker, arbitrage scanner, value betting tool, or sports analytics dashboard, you've probably experienced the same thing: You start with the exciting part. The idea. The algorithm. The UI. The business logic. And then reality hits. The Hidden Problem Nobody Talks About Most developers assume the hardest part of a betting-related project is the prediction model or arbitrage logic. In practice, the real challenge is data infrastructure. Before your project can calculate anything, you need: Live events Accurate odds Multiple bookmakers Consistent market structures Historical updates Reliable refresh rates And suddenly your "weekend project" turns into a full-time data engineering job. The Scraping Trap Most developers begin by scraping bookmaker websites. At first it seems simple: Open DevTools Find the API request Parse the response Save the data Done, right? Not quite. Within a few weeks you'll likely encounter: Changed endpoints Rate limits Cloudflare protection Different JSON formats Missing markets Broken parsers Increased maintenance costs Instead of improving your product, you're fixing scrapers. Again. And again. And again. Every Bookmaker Speaks a Different Language Let's say you want to compare odds from five sportsbooks. You quickly discover that every provider structures data differently. One bookmaker might return: { "home" : "Liverpool" , "away" : "Arsenal" } Another might return: { "team1" : "Liverpool" , "team2" : "Arsenal" } A third one could use: { "participants" : [ "Liverpool" , "Arsenal" ] } Now multiply that problem across: dozens of bookmakers hundreds of leagues thousands of events You end up spending more time normalizing data than building features. Real-Time Data Changes Everything Many projects work perfectly during testing. Then live data arrives. Odds can move multiple times within a minute. If your system refreshes too slowly: arbitrage opportunities disappear alerts become
AI 资讯
USPS Just Broke Your Magento Shipping. Here's the Fix.
If your Magento store still depends on the old USPS Web Tools integration, you should assume your shipping rates are either already broken or one change away from breaking. That sounds dramatic, but it is the practical reality we have been seeing. USPS has moved away from the old Web Tools model and toward REST API v3 with OAuth 2.0 authentication. Magento's legacy USPS integration was built for a different era. For merchants, the symptom is simple: rates stop showing up, return inconsistently, or fail under conditions you did not use to worry about. For Magento developers, the reason is also simple: the built-in carrier module is not designed for the current USPS authentication and request model. This article explains what changed, why core Magento falls over here, how to migrate cleanly, and what to watch for whether you choose an extension or a custom build. What changed: USPS Web Tools is not the same platform anymore Historically, Magento's USPS integration talked to Web Tools-style USPS endpoints: structured shipping requests, legacy authentication, and XML responses. That is not the model USPS wants merchants using now. The modern USPS stack is based on: REST API v3 endpoints OAuth 2.0 for authentication Different request and response payloads Different onboarding and credential management patterns That shift matters because it is not just a URL update. It changes authentication, token handling, and request structure. In practical terms, a migration now means: Getting the right USPS developer credentials Exchanging those credentials for OAuth access tokens Updating the carrier request layer to use REST payloads Mapping the new response format back into Magento shipping methods If you skip any of that and try to "patch" the old module with endpoint changes, you are going to waste time. Why Magento 2's built-in USPS module no longer works Magento's built-in USPS module was not architected around OAuth-backed REST API calls. It expects a legacy carrier contract
AI 资讯
Um resumo sobre o padrão de segurança HMAC
Definição O HMAC (Hash-based Message Authentication Code) é um mecanismo de segurança que permite verificar a integridade e autenticidade de uma mensagem, garantindo que ela não foi alterada e que foi gerada por quem possui uma chave secreta. Ele é muito usado em autenticação de APIs, tokens e assinaturas digitais. Analogia Imagine que você envia uma carta dentro de um envelope lacrado com um selo exclusivo que só você e o destinatário conhecem a forma de produzir. Se alguém abrir a carta e alterar qualquer palavra, o selo não vai mais bater com o original. O HMAC funciona exatamente assim: ele “lacra” os dados com uma assinatura impossível de reproduzir sem a chave secreta. Exemplo sem HMAC (inseguro) $payload = [ 'user' => 'joao' , 'exp' => time () + 300 ]; // token simples sem proteção $token = base64_encode ( json_encode ( $payload )); Problema Qualquer pessoa pode: decodificar o token alterar exp reencodar e enganar o sistema Exemplo com HMAC (seguro) $payload = [ 'user' => 'joao' , 'exp' => time () + 300 ]; $secret = 'chave_super_secreta' ; $signature = hash_hmac ( 'sha256' , json_encode ( $payload [ 'user' ]) . '|' . $payload [ 'exp' ], $secret ); $payload [ 'sig' ] = $signature ; $token = base64_encode ( json_encode ( $payload )); Validação do lado do servidor $payload = json_decode ( base64_decode ( $_GET [ 'token' ]), true ); $check = hash_hmac ( 'sha256' , json_encode ( $payload [ 'user' ]) . '|' . $payload [ 'exp' ], $secret ); if ( ! hash_equals ( $check , $payload [ 'sig' ])) { die ( "Token inválido" ); }
AI 资讯
Migrating From Transactional Email to Agent Accounts
This is what most agent email code looks like today: // SendGrid / Resend / Postmark — outbound only await sendgrid . send ({ to : " prospect@example.com " , from : " outreach@yourcompany.com " , subject : " Following up on your demo request " , html : " <p>Hi Alice — wanted to follow up on...</p> " , }); // That's it. If Alice replies, the agent never sees it. The send works fine. The problem is everything after: when Alice replies, that reply bounces, lands at a no-reply nobody reads, or hits a human inbox the agent can't reach programmatically. The agent is talking into a void. Transactional providers were built for receipts and password resets — one-way mail — and an agent that's supposed to hold a conversation needs a receive path those APIs simply don't have. Agent Accounts (a beta feature from Nylas) close that gap with a full hosted mailbox: send and receive, with threading, webhooks, and folders built in. Here's what the migration actually involves. The delta, honestly Outbound barely changes — it's still an API call. The new parts are everything transactional providers never gave you: Concern Transactional provider Agent Account Outbound API call Same — POST /messages/send Inbound None (or polling a shared inbox) Replies land automatically, fire message.created Threading You track Message-ID yourself Headers preserved, threads grouped automatically Reply detection Parse forwards, poll Webhook within seconds of arrival DNS SPF/DKIM/DMARC for the provider MX, SPF, DKIM, DMARC for the mailbox host Provision the mailbox One call creates the account; the response includes a grant_id that identifies it on every later request: curl --request POST \ --url "https://api.us.nylas.com/v3/connect/custom" \ --header "Authorization: Bearer $NYLAS_API_KEY " \ --header "Content-Type: application/json" \ --data '{ "provider": "nylas", "settings": { "email": "outreach@agents.yourcompany.com" } }' (Or nylas agent account create outreach@agents.yourcompany.com from the CLI.) C
AI 资讯
Hurl vs Postman: Git-Friendly API Testing With Proxy-Aware Egress (2026)
TL;DR: You'll learn how to replace Postman collections with plain-text Hurl files that live in Git, run in CI, and test your API’s geo behavior from any country. Debugging API issues always boils down to taking the tests you already have, running them from a different network or region, and comparing what your API receives. But I bet most of us can’t actually do that right away because our test infrastructure itself is fragmented. Your CI could be using a different config entirely from the “correct” one on a local dev machine, and half the collections may still point to a staging URL that changed months ago. Postman doesn’t produce diff-friendly artifacts, so even figuring out what changed is a full-on investigation. If any of that sounds familiar, I’d recommend finally taking the big step and replacing your Postman collection with Hurl — a command-line HTTP test runner where tests are plain **.hurl** text files that live in Git. For this tutorial, I’ll also walk you through multi-region testing — how to run those tests using a proxy to get a German egress IP, and see what the API actually returns from there. Everything below is self-contained, you’ll only need a new Git repo, then create the tests (three plaintext files.) The Test Suite at a Glance Create a folder (name it whatever you like — hurl-api-tests works) and these are the files we're going to be creating at its root . That folder is your Git repo root; paths in commands and CI are relative to it. Note how we’re using multiple .env files. If you're new to API testing, you'll find out why in a bit. hurl-api-tests/ ├── tests/ │ ├── health.hurl # smoke test -- Makes sure Hurl works, basic asserts. Skip if you want │ ├── auth-flow.hurl # Tests chaining + jsonpath capture + Bearer header │ └── geo-detail.hurl # Tests two egress profiles, real country/ASN diff (direct or proxied) ├── .env.local.example ├── .env.ci.example ├── .env.proxy-de.example ├── run-tests.mjs # cross-platform runner └── .github/workflows/a
AI 资讯
KI-Agent Tool-Aufrufe mit Apidog testen: Vor Produktionsausfällen
Ein KI-Agent ist nur so zuverlässig wie die APIs, die er aufruft. Das Modell wählt ein Tool aus, füllt Argumente ein und sendet eine Anfrage. Wenn diese Anfrage fehlschlägt, die falsche Form zurückgibt oder hängen bleibt, trifft Ihr Agent eine selbstbewusste Entscheidung auf Basis schlechter Daten. Produktions-Agenten stehen und fallen deshalb mit einer getesteten Tool- und API-Schicht. Apidog noch heute ausprobieren Diese Anleitung zeigt, wie Sie einen Agenten erstellen, der reale Tools aufruft, und wie Sie Apidog als API-Schicht und Testumgebung verwenden. Sie definieren Tool-Endpunkte, mocken sie für die Offline-Entwicklung und schreiben Assertions, die fehlerhafte Tool-Aufrufe abfangen, bevor sie Benutzer erreichen. Was ein Agent auf der API-Ebene tatsächlich tut Reduziert auf die technische Schleife passiert Folgendes: Das Modell erhält ein Benutzerziel und eine Liste verfügbarer Tools. Es gibt einen Tool-Aufruf zurück: Tool-Name plus JSON-Argumente. Ihr Code führt den Aufruf aus, meist als HTTP-Request. Das API-Ergebnis geht zurück an das Modell. Das Modell ruft ein weiteres Tool auf oder antwortet dem Benutzer. Die kritischen Fehler entstehen fast immer in Schritt 3 und 4: Das Modell halluziniert ein Argument. Die API gibt 400 , 422 , 429 oder 500 zurück. Das Antwortschema hat sich geändert. Der Request läuft in ein Timeout. Eine Ratenbegrenzung greift mitten in der Agenten-Schleife. Wenn Sie KI-Agenten als neue API-Konsumenten betrachten, wird klar: Ihr Agent ist ein API-Client. Er braucht dieselbe Teststrenge wie jeder andere produktive Client. Die Arbeit besteht aus zwei Teilen: Tools als reale, testbare API-Operationen definieren. Prüfen, ob der Agent diese Tools unter guten und schlechten Bedingungen korrekt aufruft. Schritt 1: Tools als reale API-Operationen entwerfen Definieren Sie jedes Tool zuerst als API-Endpunkt in Apidog. Behandeln Sie Tool-Schema und API-Schema als denselben Vertrag. Beispiel: Tool: get_weather API-Operation: GET /weather Paramet
AI 资讯
One Agent Identity Per Customer: Multi-Tenant Email
Provisioning a tenant-scoped email identity for your SaaS is one POST: curl --request POST \ --url "https://api.us.nylas.com/v3/connect/custom" \ --header "Authorization: Bearer <NYLAS_API_KEY>" \ --header "Content-Type: application/json" \ --data '{ "provider": "nylas", "workspace_id": "<WORKSPACE_ID>", "settings": { "email": "scheduling@customer-a.com" } }' No OAuth dance, no refresh token — just an address on a registered domain. The response comes back already valid: { "request_id" : "5967ca40-a2d8-4ee0-a0e0-6f18ace39a90" , "data" : { "id" : "b1c2d3e4-5678-4abc-9def-0123456789ab" , "provider" : "nylas" , "grant_status" : "valid" , "email" : "scheduling@customer-a.com" , "scope" : [], "created_at" : 1742932766 } } The data.id is a grant_id that works with every existing Nylas endpoint, and the account is live immediately. That's the primitive behind a multi-tenant pattern worth knowing: one Agent Account per customer, on each customer's own verified domain, all managed from a single application. (Agent Accounts are in beta, so the surface may shift before GA.) The architecture in one paragraph Your app runs scheduling@customer-a.com , scheduling@customer-b.com , and so on — same code path, different identities. Each account has its own policy, its own send quota, and its own sender reputation. A single application can manage accounts across an unlimited number of registered domains, so tenant count is a billing question, not an architectural one. Customer A's deliverability problems stay Customer A's; nothing they do contaminates Customer B's mail. Domains: register once, mint accounts forever The provisioning docs lay out two domain strategies you can mix freely in one application: Strategy Address format Setup Trial domain alias@<your-application>.nylas.email None — instant Your own domain alias@yourdomain.com MX + TXT records at the DNS provider For the per-customer pattern, each tenant brings their domain. You register it once per organization (picking the US
AI 资讯
Extract OTP Codes From Email, Automatically
What does your automation do when the login flow it's driving sends a six-digit code instead of a confirmation link? For most teams the honest answer is "a human goes and checks a shared inbox," which is a strange bottleneck to leave in the middle of an otherwise fully automated pipeline. There's a cleaner shape: the agent owns the mailbox the code lands in. With a Nylas Agent Account — a hosted mailbox controlled entirely through the API, currently in beta — the OTP email arrives, a webhook fires, your handler extracts the code, and whatever orchestrates the login gets it back. No human, no inbox-checking Slack message, no screen-scraping Gmail. Step one: make sure it's the right email A message.created webhook fires on every inbound message, so the first job is filtering down to the one that actually carries the code. The recipe uses two signals together — sender domain and a subject heuristic: app . post ( " /webhooks/otp " , async ( req , res ) => { res . status ( 200 ). end (); const event = req . body ; if ( event . type !== " message.created " ) return ; const msg = event . data . object ; if ( msg . grant_id !== AGENT_GRANT_ID ) return ; const sender = msg . from ?.[ 0 ]?. email ?? "" ; const subject = msg . subject ?? "" ; const senderMatches = sender . endsWith ( " @no-reply.example.com " ); const subjectLooksRight = /code|verif|one. ? time|passcode/i . test ( subject ); if ( ! senderMatches || ! subjectLooksRight ) return ; await handleOtp ( msg . id ); }); Neither check alone is enough. Sender-only matching trips on welcome emails from the same domain; subject-only matching trips on anything that mentions "verification." Regex first, LLM second Most OTP emails follow one of a few shapes: a standalone 4–8 digit number, or a code after a label like "Your code is:". Three patterns, tried in order from most to least specific, cover the vast majority of services: const patterns = [ / (?: code|passcode|one [\s - ]? time )[^\d]{0,20}(\d{4,8}) /i , // "Your code
AI 资讯
Ephemeral Inboxes: Spin Up a Mailbox Per Test Run
Two CI workers kick off at the same moment. Both sign up a test user, both poll the shared QA Gmail account for "the" verification email, and worker #7 grabs the message that belonged to worker #12. The test passes. The wrong test. You spend an afternoon staring at a green build that should've been red. Shared inboxes are the single biggest source of flakiness in email-dependent E2E tests, and every workaround — catch-all forwarding rules, label rules scoped per PR, OAuth tokens living on the runner — adds another moving part that breaks on its own schedule. The fix is structural: every test gets its own address, on infrastructure your suite provisions and destroys. One wildcard, infinite addresses The E2E email testing recipe sets this up with one CLI command: nylas inbound create e2e You get back an inbox ID and a wildcard pattern shaped like e2e-*@yourapp.nylas.email . From there, each test mints a unique address under the wildcard — e2e-<uuid>@yourapp.nylas.email — and there's nothing to provision per address. You don't pay or configure per address either; the wildcard is just a convention, so burn UUIDs freely. Mail flows through MX records hosted on the Nylas side, which means zero DNS work in your own zone (the tradeoff: addresses live under *.nylas.email ). The Playwright fixture is two pieces — an address minter and a poller: export const test = base . extend < Fixtures > ({ testEmail : async ({}, use ) => { await use ( `e2e- ${ randomUUID ()} @yourapp.nylas.email` ); }, pollInbox : async ({ testEmail }, use ) => { const poll = async ( timeoutMs = 30 _000 ) => { const deadline = Date . now () + timeoutMs ; while ( Date . now () < deadline ) { const out = execSync ( `nylas inbound messages ${ process . env . INBOX_ID } --json --limit 50` , ). toString (); const match = JSON . parse ( out ). find (( m ) => m . to . some (( t ) => t . email === testEmail ), ); if ( match ) return match ; await new Promise (( r ) => setTimeout ( r , 1500 )); } throw new Error (
AI 资讯
Give Your AI Agent Its Own Email Address (Not Access to Yours)
Most "AI agent + email" tutorials start the same way: connect the agent to a human's inbox over OAuth, hope the token doesn't expire mid-run, and pray the agent never replies to the wrong thread on someone's behalf. There's a different model: give the agent its own email address. Nylas recently shipped Agent Accounts (currently in beta) — fully functional, Nylas-hosted mailboxes you create and control entirely through the API. Each one is a real name@company.com address that sends, receives, hosts calendar events, and RSVPs to invitations. To anyone interacting with it, it's indistinguishable from a human-operated account. I work on the docs at Nylas, so I've spent a lot of time with this API. Here's a tour of what it does and how to get a mailbox running in a few minutes. Why not just connect the agent to a human inbox? You can — that's what OAuth grants are for, and they're the right tool when the agent works on behalf of a person. But a lot of agent workflows want a first-class identity instead: System mailboxes ( sales@ , support@ , scheduling@ ) that your app owns end-to-end. No OAuth consent screen, no user offboarding breaking your integration. Ephemeral inboxes for test automation — provision a fresh address per run, sign up for a service, grab the OTP from the verification email, tear it down. Per-customer identities in multi-tenant apps: scheduling@customer-a.com , scheduling@customer-b.com , each with its own send quota and sender reputation, all in one Nylas application. A scheduling bot with its own calendar that proposes slots, sends invites, and shows up as a normal participant in Google Calendar, Microsoft 365, and Apple Calendar. The key design decision: an Agent Account is just another grant . It gets a grant_id that works with every existing Nylas endpoint — Messages, Drafts, Threads, Folders, Attachments, Calendars, Events, Webhooks. If you've already built against connected accounts, nothing new to learn. Create a mailbox with one API call Every
AI 资讯
How to Convert JSON to XML Without Breaking Your Integration
Working with modern APIs means living in JSON. But the moment your project touches a legacy enterprise system - a bank, a government service, or a SOAP endpoint that hasn't changed in a decade - you're suddenly dealing with XML. The challenge isn't just swapping syntax; it's understanding where the two formats are structurally incompatible, and what breaks silently when you ignore that. Why JSON and XML Don't Simply Map to Each Other JSON is compact and type-aware - it distinguishes between numbers, booleans, strings, and arrays natively. XML is verbose, treats all content as text, and has no concept of arrays. It only has repeated sibling elements. This gap is where most conversion bugs are born. A JSON array with just one item can silently become a plain object if your converter doesn't handle the edge case explicitly. The Three Biggest Conversion Pitfalls First is array ambiguity - XML has no array type, so a JSON array becomes repeated sibling elements. A single-item array is indistinguishable from a plain object unless your converter explicitly preserves the list context. Second is type erasure - XML flattens numbers, booleans, and strings into plain text, destroying the type information that many downstream systems depend on. Third is the single root element rule - JSON can have multiple top-level keys, but every valid XML document must have exactly one root element wrapping everything else. Handling Arrays the Right Way Always nest array items inside a named parent element. A JSON users array should produce a parent element containing individual child elements. This structure makes the list unambiguous to any downstream XML parser and prevents silent data loss during round-trips. Escaping Special Characters Characters that are perfectly valid inside a JSON string will break an XML parser immediately. Your conversion logic must escape these four: less-than becomes <, greater-than becomes >, ampersand becomes &, and double-quote becomes ". Skipping even one of
AI 资讯
From OpenSSL to One Click: Meet the Payneteasy Key Pair Factory
Connecting to a payment gateway rarely fails because of business logic. More often, it fails at the very first technical step: authentication. If you’ve ever worked with payment APIs, you know the drill. Before sending a single request, you need to generate a cryptographic key pair and sign every request correctly. Sounds straightforward—until you actually try to do it. The hidden hurdle in every integration To securely call the Payneteasy API, each request must be signed. That means: Generating an RSA key pair (usually via OpenSSL) Converting between PKCS#1 and PKCS#8 formats Building a correct signature base string Percent-encoding everything properly Signing with RSA-SHA256 or HMAC-SHA1 Assembling the Authorization header One small mistake—a missing character, wrong encoding, or incorrect format—and your request gets rejected. For teams without deep cryptography expertise, this step alone can turn a one-day integration into a week-long debugging session. If you’re curious, the full manual process is documented here: https://doc.payneteasy.com/integration/general_api_usage/request_authentication_methods/oauth.html#generating-key-pair The solution: Key Pair Factory We built the Payneteasy Key Pair Factory to remove this bottleneck entirely. Instead of dealing with OpenSSL commands and key formats, you can generate everything you need in just a few clicks. What it does: Generates a ready-to-use RSA key pair Ensures correct formatting for Payneteasy APIs Eliminates manual conversion and configuration errors Keeps the private key on your side Provides a public key for request verification No cryptography expertise required. The tool is open-source and available on GitHub: https://github.com/payneteasy/key-pair-factory Why this matters This is not just about convenience—it directly impacts integration speed and success. With the Key Pair Factory, you get: Faster onboarding Fewer integration errors Less back-and-forth with support teams A smoother developer experience I
AI 资讯
Using PostAll's API to Automate Your Content Workflow: A Getting-Started Guide
I didn't set out to build a content API. I set out to stop copy-pasting. Every week, the same ritual: open a doc, stare at a blank page, write a headline, delete it, write it again. Multiply that by every client, every product page, every email drip campaign. I wasn't doing creative work — I was doing assembly-line work while pretending it was creative. PostAll started as a script I wrote to stop doing that. The API is what that script became after other developers asked if they could use it too. This guide walks you through integrating PostAll's API into your own workflow — authentication, the endpoints you'll actually use, real working code in both Python and Node.js, and the specific places things will break before they work. By the end, you'll have a functioning pipeline that generates formatted, CMS-ready content programmatically. What you'll build A script that takes a list of content briefs (keywords, tone, target length) and returns publish-ready content — with proper formatting, metadata, and error handling for the rate limits you'll hit in production. Here's the shape of what you're building: [ CSV of briefs ] → [ PostAll API ] → [ formatted content objects ] → [ your CMS / database ] The full working code for both languages is at the end of each section. I'll explain the interesting parts inline. Prerequisites A PostAll account with API access enabled (free tier works for this guide — rate limits noted below) Node.js 18+ or Python 3.10+ Basic familiarity with async/await in either language An HTTP client: axios or native fetch for Node, httpx for Python Step 1: Authentication PostAll uses API key authentication. Every request needs your key in the Authorization header. Get your key: Dashboard → Settings → API Keys → Generate New Key Store it as an environment variable. Never hardcode it. export PostAll_API_KEY = "postall_live_xxxxxxxxxxxxxxxxxxxx" Your key has two prefixes: postall_live_ for production, postall_test_ for the sandbox. The sandbox returns r
AI 资讯
Build a versioned Laravel API with auto-generated OpenAPI docs in 10 minutes
TL;DR — We'll install dskripchenko/laravel-api , write one controller, and end up with a versioned API ( /api/v1/... ) and interactive OpenAPI 3.0 docs at /api/doc — generated from the docblock you'd write anyway. Then we'll ship a v2 without copy-pasting a single controller. The problem Two things rot in every growing Laravel API: Versioning. v1 ships, then v2 needs to change three endpoints but keep the other twenty. You either copy-paste a V2 folder (and now bugfixes live in two places) or bolt if ($version === 2) branches into your controllers. Docs. The OpenAPI spec drifts from the code the moment you merge. Annotation libraries ( #[OA\Get(...)] , giant YAML files) ask you to describe your API twice — once in code, once in attributes. This package's bet: your controller already describes itself . The method name, the request fields, the response shape — write them once, as a normal PHPDoc, and let the package derive routes and docs from it. Versioning becomes plain PHP inheritance. Let's build it. What we'll build A tiny tasks API: POST /api/v1/task/list — list tasks POST /api/v1/task/create — create one interactive docs at GET /api/doc (raw spec per version at /api/doc/{version} ) then a v2 that adds an endpoint without touching v1 Total: ~4 small files. Step 0 — Install composer require dskripchenko/laravel-api Publish the config (optional, but handy to see the knobs): php artisan vendor:publish --tag = laravel-api-config // config/laravel-api.php return [ 'prefix' => 'api' , // → /api/... 'uri_pattern' => '{version}/{controller}/{action}' , 'available_methods' => [ 'get' , 'post' , 'put' , 'patch' , 'delete' ], 'openapi_path' => 'public/openapi' , 'doc_middleware' => [], // lock down /api/doc here ]; Step 1 — Write a controller Nothing exotic — it extends the package's ApiController , which gives you response helpers ( success() , error() , validationError() , created() , noContent() , notFound() ). The docblock is the documentation : <?php namespace App\Api
开发者
We Hosted OpenClaw So You Don't Have To
TLDR: we just launched free OpenClaw hosting. One-click deploy, no infrastructure to manage, only pay...
AI 资讯
I Built My Own API Gateway in Rust — Here's What I Learned
Every backend project I've worked on eventually hits the same wall. You start clean — one service, simple routes, everything works. Then slowly the requirements creep in. "We need rate limiting." "Can we add auth middleware?" "What happens when the user service goes down — does it take everything else with it?" You either bolt these things onto every service individually, copy-paste the same middleware across projects, or pay for a managed gateway like Kong or AWS API Gateway and hope it does what you need. I wanted to actually understand how these things work under the hood. So I'm building one — and this is what I've learned so far. What is Ferrox? Ferrox is a self-hosted, programmable API gateway written entirely in Rust. It sits in front of your backend services and handles everything a production system needs in one place: Dynamic routing — point any path prefix to any upstream service Authentication — JWT and API key validation on protected routes Rate limiting — Redis-backed per-IP and per-API-key limiting Circuit breaking — stops hammering a dead upstream service Response caching — Redis-backed TTL cache per route Real-time observability — WebSocket dashboard with live request stats Prometheus metrics — plug straight into Grafana The idea is simple. Instead of this: Client → Service A (has its own auth, rate limiting, logging) Client → Service B (has its own auth, rate limiting, logging) Client → Service C (has its own auth, rate limiting, logging) You get this: Client | v FERROX (auth, rate limiting, circuit breaking, logging — once) | +--------+--------+ | | | Svc A Svc B Svc C (clean) (clean) (clean) Your services stay clean. Ferrox handles the cross-cutting concerns. Why Rust? Honest answer — I already knew Rust from my backend work. But for a gateway specifically, it felt like the obvious choice. A gateway sits on the critical path of every single request. Every millisecond of latency it adds is latency your users feel. You need predictable performance